package cn.assumejson.springframework.beans.factory.support;

import cn.assumejson.springframework.beans.factory.BeansException;
import cn.assumejson.springframework.beans.factory.FactoryBean;
import cn.assumejson.springframework.beans.factory.config.DefaultSingletonBeanRegistry;
import cn.hutool.core.util.ObjectUtil;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 用于注册FactoryBean
 *
 * @author Mr. Li
 * @version 1.0
 * @since 1.0 2021/12/1 14:11
 */
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
    /**
     * Cache of singleton objects created by FactoryBeans: FactoryBean name --> object
     */
    private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

    protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
        Class<?> object = factoryBean.getObjectType();
        return (object != NULL_OBJECT ? object : null);
    }

    protected Object getCachedObjectForFactoryBean(String beanName) {
        return this.factoryBeanObjectCache.get(beanName);
    }

    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws Exception {
        if (factory.isSingleton() && containsSingleton(beanName)) {
            synchronized (getSingletonMutex()) {
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (ObjectUtil.isNull(object)) {
                    object = doGetObjectFromFactoryBean(factory, beanName);
                    object = object != null ? object : NULL_OBJECT;
                }
                return object;
            }
        } else {
            return doGetObjectFromFactoryBean(factory, beanName);
        }
    }

    private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws Exception {
        return factory.getObject();
    }

}
